import { isObject, isArray } from "../checker";

/**
 * JS对象深度合并
 */
function _deepMerge(origin: { [k: string]: any }, sourceObj?: { [k: string]: any }) {
    // 如果不是 对象, 就返回 空对象
    if (!isObject(origin)) {
        return {};
    }
    // copy一下 防止 传入的 对象 修改, 引起这个改变
    let target = deepClone(origin);
    if (!isObject(sourceObj)) {
        return target;
    }

    let source = sourceObj!;
    let allKeys = Object.keys(source);
    for (let i = 0; i < allKeys.length; i++) {
        let prop = allKeys[i];
        if (prop in target) {
            if (typeof target[prop] !== "object") {
                // 如果不是 对象的话,  就直接 覆盖
                target[prop] = source[prop];
            } else {
                // 如果 传过来的 类型不是对象, 那也用 source得了
                if (typeof source[prop] !== "object") {
                    target[prop] = source[prop];
                } else {
                    // 是数组哦
                    if (target[prop].concat && source[prop].concat) {
                        target[prop] = target[prop].concat(source[prop]);
                    } else if (isArray(target[prop]) || isArray(source[prop])) {
                        // 有一个是数组,  类型不一样,  直接 覆盖吧
                        target[prop] = source[prop];
                    } else {
                        // 都不是数组
                        // 那 对象 和 对象 合并下
                        target[prop] = _deepMerge(target[prop], source[prop]);
                    }
                }
            }
        } else {
            target[prop] = source[prop];
        }
    }

    return target;
}

/**
 * 合并 配置项
 * @param {Object} configuration1
 * @param {Object} configuration2
 */
function merge(configuration1: { [k: string]: any }, configuration2?: { [k: string]: any }) {
    let result = _deepMerge(configuration1, configuration2);
    return result;
}

/** 实现 深拷贝
 * @param {Object} obj
 */
function deepClone(obj: any) {
    if ([null, undefined, NaN, false].includes(obj)) return obj;
    if (typeof obj !== "object" && typeof obj !== "function") {
        //原始类型直接返回
        return obj;
    }
    let o: any = isArray(obj) ? [] : {};
    for (let i in obj) {
        if (obj.hasOwnProperty(i)) {
            o[i] = typeof obj[i] === "object" ? deepClone(obj[i]) : obj[i];
        }
    }
    return o;
}

export { merge, deepClone };
